﻿using System;
using System.Configuration;
using System.Globalization;
using System.Threading;

using BizElements.BusinessLayer;

namespace BizElements.Web
{
    #region Documentation.
    /// <summary>Reads customized user interface messages for <see cref="SearchFilter"/> control from a <see cref="ITextSource"/> object.</summary>
    /// <remarks><para>Values returned from SearchFilterTextSource objects override values set through SearchFilter's properties. If a 
    /// SearchFilterTextSource property returns null then no override occurs, i.e. a value set through SearchFilter property or a skin file is used.</para>
    /// <para>Settings are read from the application's config file as shown in the following example:
    /// <code>
    /// <configuration>
    ///     <appSettings>
    ///         <add key="BizElements.Web.SearchFilterTextSource.GetDefaultTextSourceMethodAssembly" value="BizElements.Web" />
    ///         <add key="BizElements.Web.SearchFilterTextSource.GetDefaultTextSourceMethodClass" value="BizElements.Web.CommonGetters"/>
    ///         <add key="BizElements.Web.SearchFilterTextSource.GetDefaultTextSourceMethodName" value="GetMessageSource" />
    ///         <add key="BizElements.Web.SearchFilterTextSource.DefaultKeyPrefix" value="SearchFilterTextSource_" />
    ///         <add key="BizElements.Web.SearchFilterTextSource.GetUiCultureAssembly" value="BizElements.Web" />
    ///         <add key="BizElements.Web.SearchFilterTextSource.GetUiCultureClass" value="BizElements.Web.CommonGetters"/>
    ///         <add key="BizElements.Web.SearchFilterTextSource.GetUiCultureMethodName" value="GetUiCulture" />
    ///     </appSettings>
    /// </configuration>
    /// </code></para>
    /// </remarks>
    #endregion
    public class SearchFilterTextSource : ISearchFilterTextSource
    {
        #region Configuration.

        /// <summary>A method which gets default source of captions configured in application configuration file. If not set then <see cref="CommonGetters.GetMessageSource()"/> is used.</summary>
        /// <remarks>Settings are read from the application's config file as shown in the following example:
        /// <code>
        /// <configuration>
        ///     <appSettings>
        ///         <add key="BizElements.Web.SearchFilterTextSource.GetDefaultTextSourceMethodAssembly" value="BizElements.Web" />
        ///         <add key="BizElements.Web.SearchFilterTextSource.GetDefaultTextSourceMethodClass" value="BizElements.Web.CommonGetters"/>
        ///         <add key="BizElements.Web.SearchFilterTextSource.GetDefaultTextSourceMethodName" value="GetMessageSource" />
        ///     </appSettings>
        /// </configuration>
        /// </code>
        /// </remarks>
        public static readonly Delegates.Function<ITextSource> GetDefaultTextSource;

        /// <summary>Default key prefix for properties/captions retrieved from text source. Defaut is <b>SearchFilter_</b></summary>
        /// <remarks>Settings are read from the application's config file as shown in the following example:
        /// <code>
        /// <configuration>
        ///     <appSettings>
        ///         <add key="BizElements.Web.SearchFilterTextSource.DefaultKeyPrefix" value="SearchFilter_" />
        ///     </appSettings>
        /// </configuration>
        /// </code>
        /// </remarks>
        public static readonly string DefaultKeyPrefix;

        /// <summary>A method which gets a culture used by current user. If not set then <see cref="CommonGetters.GetUiCulture()"/> is used.</summary>
        /// <remarks>Settings are read from the application's config file as shown in the following example:
        /// <code>
        /// <configuration>
        ///     <appSettings>
        ///         <add key="BizElements.Web.SearchFilterTextSource.GetUiCultureAssembly" value="BizElements.Web" />
        ///         <add key="BizElements.Web.SearchFilterTextSource.GetUiCultureClass" value="BizElements.Web.CommonGetters"/>
        ///         <add key="BizElements.Web.SearchFilterTextSource.GetUiCultureMethodName" value="GetUiCulture" />
        ///     </appSettings>
        /// </configuration>
        /// </code>
        /// </remarks>
        public static readonly Delegates.Function<CultureInfo> GetUiCulture;

        static SearchFilterTextSource()
        {
            DefaultKeyPrefix = ConfigurationManager.AppSettings["BizElements.Web.SearchFilterTextSource.DefaultKeyPrefix"];
            if (string.IsNullOrEmpty(DefaultKeyPrefix))
                DefaultKeyPrefix = "SearchFilter_";

            GetDefaultTextSource = ReflectionUtil.TryCreateDelegateFromAppSettings<Delegates.Function<ITextSource>>(
                "BizElements.Web.SearchFilterTextSource.GetDefaultTextSourceMethodAssembly",
                "BizElements.Web.SearchFilterTextSource.GetDefaultTextSourceMethodClass",
                "BizElements.Web.SearchFilterTextSource.GetDefaultTextSourceMethodName");
            if (GetDefaultTextSource == null)
                GetDefaultTextSource = CommonGetters.GetMessageSource;

            GetUiCulture = ReflectionUtil.TryCreateDelegateFromAppSettings<Delegates.Function<CultureInfo>>(
                "BizElements.Web.SearchFilterTextSource.GetUiCultureAssembly",
                "BizElements.Web.SearchFilterTextSource.GetUiCultureClass",
                "BizElements.Web.SearchFilterTextSource.GetUiCultureMethodName");
            if (GetUiCulture == null)
                GetUiCulture = CommonGetters.GetUiCulture;
        }

        #endregion

        #region Constructors.

        /// <summary>Initializes a new instance of the <b>SearchFilterTextSource</b> class.</summary>
        /// <remarks><see cref="TextSource"/> property or <see cref="GetDefaultTextSource"/> delegate must be initialized before <b>SearchFilterTextSource</b> can be used.</remarks>
        public SearchFilterTextSource()
        {
            this.keyPrefix = DefaultKeyPrefix;
        }

        /// <summary>Initializes a new instance of the <b>SearchFilterTextSource</b> class.</summary>
        /// <param name="textSource">The source of captions. <b>null</b> is not allowed.</param>
        public SearchFilterTextSource(ITextSource textSource)
        {
            if (textSource == null) throw new ArgumentNullException("textSource", "textSource may not be a null reference.");
            this.textSource = textSource;
            this.keyPrefix = DefaultKeyPrefix;
        }

        /// <summary>Initializes a new instance of the <b>SearchFilterTextSource</b> class.</summary>
        /// <param name="textSource">The source of captions. <b>null</b> is not allowed.</param>
        /// <param name="keyPrefix">Key prefix for properties/captions retrieved from text source.</param>
        public SearchFilterTextSource(ITextSource textSource, string keyPrefix)
        {
            if (textSource == null) throw new ArgumentNullException("textSource", "textSource may not be a null reference.");
            this.textSource = textSource;
            this.keyPrefix = keyPrefix;
        }

        #endregion

        #region TextSource.

        private string GetProperty(string property)
        {
            if (this.KeyPrefix != null)
                return this.TextSource.GetString(string.Format("{0}{1}", this.KeyPrefix, property), GetCulture());
            else
                return this.TextSource.GetString(property, GetCulture());
        }

        private static CultureInfo GetCulture()
        {
            if (GetUiCulture != null)
                return GetUiCulture();
            else
                return Thread.CurrentThread.CurrentUICulture;
        }

        ITextSource textSource;

        private void EnsureTextSource()
        {
            if (this.textSource == null)
            {
                if (GetDefaultTextSource == null)
                    throw new InvalidOperationException("GetDefaultTextSource delegate is not configured in application's configuration file.");

                this.textSource = GetDefaultTextSource();
            }
        }

        /// <summary>Gets or sets source of captions.</summary>
        public ITextSource TextSource
        {
            get
            {
                EnsureTextSource();
                return this.textSource;
            }
            set
            {
                if (value == null) throw new ArgumentNullException("value", "value may not be a null reference.");
                this.textSource = value;
            }
        }

        string keyPrefix;

        /// <summary>Gets or sets key prefix for properties/captions retrieved from text source.</summary>
        /// <value>String; default is null.</value>
        /// <remarks>If prefix is not set, then it is assumed that property names are used in text source. 
        /// For example, if no prefix is defined, then key used for <b>AddWithOrText</b> property would be <b>AddWithOrText</b>.
        /// If, for example, key prefix is set to <b>MyFilter_</b>, then the value is stored under <b>MyFilter_AddWithOrText</b> key.</remarks>
        public string KeyPrefix
        {
            get { return this.keyPrefix; }
            set { this.keyPrefix = value; }
        }

        #endregion

        #region ISearchFilterTextSource.

        /// <summary>Gets the Text property for generated CheckBox controls which indicates whether filter created for a search field is combined using logical OR.</summary>
        public string AddWithOrText
        {
            get { return GetProperty("AddWithOrText"); }
        }

        /// <summary>Gets the Text property for generated CheckBox controls which indicates whether filter created for a search field is inverted.</summary>
        public string InvertFilterText
        {
            get { return GetProperty("InvertFilterText"); }
        }

        /// <summary>Gets the Text property for generated CheckBox controls which indicates whether filter created for a search field will try to find any of the specified words/phrases.</summary>
        public string AnyWordOrPhraseText
        {
            get { return GetProperty("AnyWordOrPhraseText"); }
        }

        /// <summary>Gets the caption for the Default text search mode option.</summary>
        public string TextSearchModeDefaultCaption
        {
            get { return GetProperty("TextSearchModeDefaultCaption"); }
        }

        /// <summary>Gets the caption for the BeginningOfText text search mode option.</summary>
        public string TextSearchModeBeginningOfTextCaption
        {
            get { return GetProperty("TextSearchModeBeginningOfTextCaption"); }
        }

        /// <summary>Gets the caption for the AnywhereInText text search mode option.</summary>
        public string TextSearchModeAnywhereInTextCaption
        {
            get { return GetProperty("TextSearchModeAnywhereInTextCaption"); }
        }

        /// <summary>Gets the caption for the ExactMatch text search mode option.</summary>
        public string TextSearchModeExactMatchCaption
        {
            get { return GetProperty("TextSearchModeExactMatchCaption"); }
        }

        /// <summary>Gets the Text property for generated CheckBox controls which indicates whether users can choose to look for records where the field value is not set, ie. null.</summary>
        public string IsNullText
        {
            get { return GetProperty("IsNullText"); }
        }

        /// <summary>Gets the ToolTip property for generated CheckBox controls which indicates whether users can choose to look for records where the field value is not set, ie. null.</summary>
        public string IsNullToolTip
        {
            get { return GetProperty("IsNullToolTip"); }
        }

        /// <summary>Gets the ToolTip property for generated CheckBox controls which indicates whether filter created for a search field will try to find any of the specified words/phrases.</summary>
        public string AnyWordOrPhraseToolTip
        {
            get { return GetProperty("AnyWordOrPhraseToolTip"); }
        }

        /// <summary>Gets the ToolTip property for generated CheckBox controls which indicates whether filter created for a search field is combined using logical OR.</summary>
        public string AddWithOrToolTip
        {
            get { return GetProperty("AddWithOrToolTip"); }
        }

        /// <summary>Gets the ToolTip property for generated CheckBox controls which indicates whether filter created for a search field is inverted.</summary>
        public string InvertFilterToolTip
        {
            get { return GetProperty("InvertFilterToolTip"); }
        }


        /// <summary>Gets the text caption of the open predefined filter control.</summary>
        public string OpenPredefinedFilterText
        {
            get { return GetProperty("OpenPredefinedFilterText"); }
        }

        /// <summary>Gets the caption of show advanced search options toggle button. </summary>
        public string ShowAdvancedOptionsCaption
        {
            get { return GetProperty("ShowAdvancedOptionsCaption"); }
        }

        /// <summary>Gets the caption of hide advanced search options toggle button. </summary>
        public string HideAdvancedOptionsCaption
        {
            get { return GetProperty("HideAdvancedOptionsCaption"); }
        }

        /// <summary>Gets the text caption displayed in the <b>search button</b> control.</summary>
        public string SearchButtonText
        {
            get { return GetProperty("SearchButtonText"); }
        }

        /// <summary>Gets the text caption displayed in the <b>reset button</b> control.</summary>
        public string ResetButtonText
        {
            get { return GetProperty("ResetButtonText"); }
        }

        /// <summary>Gets the text caption displayed in the <b>find filter button</b> control.</summary>
        public string FindFilterButtonText
        {
            get { return GetProperty("FindFilterButtonText"); }
        }

        /// <summary>Gets the text caption displayed in the <b>save button</b> control.</summary>
        public string SaveButtonText
        {
            get { return GetProperty("SaveButtonText"); }
        }

        #endregion
    }
}